#include<iostream>
#include<cstdio>
#include<vector>
#include<sys/wait.h>
#include<sys/types.h>
#include<cstdlib>
#include<string>
#include<unistd.h>
using std::cout;
using std::endl;
using std::vector;

typedef void (*callback_t)();  // 函数指针类型

enum 
{
    OK,        // 正确运行
    USAGE_ERR  // 错误码
};

void Task()
{
    int cnt = 5;
    while(cnt--)
    {
        printf("我是一个子进程1, pid:>%d, ppid:>%d, cnt=%d\n", getpid(), getppid(), cnt);
        sleep(1);
    }
}

void Hello()
{
    int cnt = 5;
    while(cnt--)
    {
        printf("我是一个子进程2, 在完成hello任务, pid:>%d, ppid:>%d, cnt=%d\n", getpid(), getppid(), cnt);
        sleep(1);
    }
}

// 新增任务函数3
void Work()
{
    int cnt = 5;
    while(cnt--)
    {
        printf("我是一个子进程3, 正在工作, pid:>%d, ppid:>%d, cnt=%d\n", getpid(), getppid(), cnt);
        sleep(1);
    }
}

// 新增任务函数4
void Play()
{
    int cnt = 5;
    while(cnt--)
    {
        printf("我是一个子进程4, 正在玩耍, pid:>%d, ppid:>%d, cnt=%d\n", getpid(), getppid(), cnt);
        sleep(1);
    }
}

// 对于参数一般而言
// 对于输入性参数：const &
// 对于输出性参数：*
// 对于输入输出性参数：&
template<class T>
void CreateChildProcess(int num, vector<T>* v, const vector<callback_t>& cbs)
{
    for(int i = 0; i < num; ++i)
    {
        pid_t id = fork();
        if(id == 0)  // child
        { 
            // 根据下标i选择对应的任务函数
            // 使用取模运算确保不会越界
            int task_index = i % cbs.size();
            cbs[task_index]();  // 执行对应的任务函数
            exit(0);
        }
        v->push_back(id);  // 因为v是指针，所以用箭头
        printf("创建子进程 %d，将执行任务 %lu\n", id, i % cbs.size() + 1);
    }
}

template<class T>
void WaitChild(const vector<T>& subs)
{
    for(auto& pdi : subs)
    {
        int status = 0;
        pid_t rid = waitpid(pdi, &status, 0);
        if(rid > 0)
        {
            printf("子进程为 %d, 退出码：%d\n", rid, WEXITSTATUS(status));        
            sleep(1);
        }
    }
}

// 启动多进程方案
// 要这么用：./xxx 5 ——我们要创建5个子进程
int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        cout << "用法: " << argv[0] << " <进程数量>" << endl;
        exit(USAGE_ERR);
    }
    
    int num = atoi(argv[1]);  // 使用atoi避免兼容性问题
    
    vector<pid_t> subs;  // 进程PID容器
    vector<callback_t> cbs;  // 任务函数容器
    
    // 初始化任务函数容器
    cbs.push_back(Task);
    cbs.push_back(Hello);
    cbs.push_back(Work);
    cbs.push_back(Play);
    
    cout << "可用任务函数数量: " << cbs.size() << endl;
    cout << "将创建 " << num << " 个子进程" << endl;
    
    // 创建多进程
    CreateChildProcess(num, &subs, cbs);
    
    // 等待多进程
    WaitChild(subs);
    
    cout << "所有子进程执行完毕" << endl;
    return 0;
}
